Re: preventing sequence number guessing

Darren Reed (avalon@coombs.anu.edu.au)
Wed, 25 Jan 1995 17:04:14 +1100 (EDT)

> 
> I'm certainly no security expert, but I had a fairly simple idea
> for fixing the sequence number guessing vulnerability.  Hopefully
> someone can tell me whether it's worthless or not.  Hunting season's
> open -- shoot it down at will. :-)
> 
> When OS boots up, grab lots of entropy and use MD5 to hash it
> into a 32 bit seed; initialize tcp_iss with it.  Now let the
> kernel do its normal "increment tcp_iss a little for every new
> connection and every couple of clock ticks" schtick as always.

This is a good start...

> I've only got one novel idea: instead of using tcp_iss directly
> for the SYN everytime a new TCP/IP connection is opened, send
> MD5(tcp_iss) [or maybe MD5(tcp_iss, time(NULL), ...)].

not bad either...but rather than just when it is opened, perhaps
something a bit different but very similar...

> This implements a cryptographically strong random number generator
> for the sequence numbers; then attackers would have to invert
> MD5 to predict sequence numbers.  MD5 is quite fast (is it fast
> enough?) and is completely exportable.  Code for MD5 is available
> for anonymous ftp on ripem.msu.edu /pub/crypt/other/md5.zip.
> 
> To nitpick, tcp_iss should be a full 64 bit (or even larger :-)
> data type; this is easy enough to change in the kernel: (right?)

No.  For the patch to be most useful, it should work with minimal
alteration to .o's (I've learnt this) unless you're Sun/DEC, etc.
Even then, most people will be reluctant to make these sort of
changes unless they're confident about what they're doing.

[...]
> So, am I missing some important kernel feature which shoots this
> all down?  Or is this actually a worthwhile technique?  [If it
> is worthwhile, it seems like it'd be pretty easy to code -- but
> I have no experience at kernel programming, so I haven't done it
> myself. <sigh>]

If you don't interfere with the generation of tcp_iss at the *right*
time (and remember, for some stupid reason to do with 4.2BSD, you're
limited to 31 bits) the kernel will hapily make tcp_iss 0 for you,
regardless of what your increments were in and what it started out at.

It would seem that the easiest way to "hijack" the generation of the
tcp_iss variable in the kernel is to mess with the table in in_proto.c
(which is shipped with all SunOS 4.1.x and is compiled when you generate
your own kernel).  Indeed, rather than use that program to mess with
ip_output.o and insert a wrapper, you can simply put your wrapper into
the table here and voila!  If, for example, we used the above idea,
it should be trivial to write a wrapper for tcp_input which set tcp_iss
to whatever only when it was a pure "SYN" packet coming in.  How hard
is that ?

MD5(foo)
tcp_seq foo;
{
	...
	return bar;
}

tcp_input_wrap(m)
struct mbuf *m;
{
	struct ip *ip;
	struct tcphdr *tcp;

	ip = mtod(m, struct ip *);
	tcp = (struct tcphdr *)((char *)ip + ip->ip_hl << 2);
	if (tcp->th_flags == TH_SYN)
		tcp_iss = MD5(tcp_iss);
	return tcp_input(m);
}

and in in_proto.c, we replace tcp_input with tcp_input_wrap in the
table for SOCK_STREAM.  The rest is academic...

darren